package com.zhengxing.jienci.web.aspectj;

import com.zhengxing.jienci.web.annotation.DataCheck;
import com.zhengxing.jienci.web.exception.ParamcheckException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 浪遏飞舟
 * @create 2020-04-13 17:18
 * 数据校验切面
 * 对controller层接口进行参数校验，默认参数不能为空字符串。
 * 暂时只能对Map接收的参数进行校验
 */
@Component
@Aspect
@Order(1)  //数字越小越先开始,越后结束
public class DataCheckAspect {

    //当方法参数之前加上了DataCheck注解切入
    //暂时支持下面包路径下的方法切入
    @Pointcut("execution(* com.zhengxing.*.*.controller.*ControllerL.*(..))")
    //@Pointcut("@args(com.zhengxing.jienci.web.annotation.DataCheck)")
    //@Pointcut("@args(.., com.zhengxing.jienci.web.annotation.DataCheck)")
    public void validate(){}


    @Around("validate()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //获得方法所有参数
        Object[] params = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        //获得要切入的方法
        Method method = signature.getMethod();
        //获得所有的参数上注解
        Annotation[][] annotations = method.getParameterAnnotations();
        String checkInfo = null;
        //开始校验
        out:
        for (int i = 0 ; i<annotations.length ; i++){
            Object para = params[i];
            Annotation[] paraAnn = annotations[i];
            if (para==null || paraAnn.length == 0){
                continue;
            }
            for (Annotation annotation:paraAnn){
                if (annotation.annotationType().equals(DataCheck.class)){
                    if (para instanceof Map){
                        DataCheck dataCheck = (DataCheck) annotation;
                        checkInfo = checkKey(dataCheck.value(),dataCheck.message(),dataCheck.isCheckEmpty(),(Map)para);
                        break out;
                    }
                }
            }
        }
        //是否缺参数
        if (checkInfo!=null){
             throw new ParamcheckException("你缺少这些参数:" + checkInfo);
        }
        return joinPoint.proceed();
    }

    /*
     * 校验参数
     * @param keys 需要校验的keys
     * @param message 对应的提示信息
     * @param isCheckEmpty 是否校验空串
     * @param param 参数
     * @return
      */
    public String checkKey(String[] keys,String[] message,boolean isCheckEmpty,Map param){
        List<String> lackKeys = new ArrayList<>();
        //根据有无message值提供不同的提示信息
        if (message == null || message.length == 0 || message.length != keys.length){
            for (String key:keys){
                if(isCheckEmpty){
                    if (!param.containsKey(key) || StringUtils.isEmpty((String) param.get(key))){
                        lackKeys.add(key);
                    }
                }else{
                    if (!param.containsKey(key)){
                        lackKeys.add(key);
                    }
                }
            }
        }else{
            for (int i = 0; i < keys.length; i++) {
                if (isCheckEmpty){
                    if (!param.containsKey(keys[i]) || StringUtils.isEmpty((String)param.get(keys[i]))){
                        lackKeys.add(message[i]);
                    }
                }else{
                    if (!param.containsKey(keys[i])){
                        lackKeys.add(message[i]);
                    }
                }

            }
        }
        if (lackKeys.size() > 0){
            StringBuffer lackKeysStr = new StringBuffer("[");
            int i = 0;
            for (String key: lackKeys){
                if (i < lackKeys.size()-1){
                    lackKeysStr.append(key + ",");
                }else{
                    lackKeysStr.append(key);
                }
                i++;
            }
            lackKeysStr.append("]");
            return lackKeysStr.toString();
        }
        return null;
    }



}
